# -*- coding: utf-8 -*-
import os,sys,re
import subprocess
import time

from . import gadget

##################################################################
#################### RAR SETTING #################################
##################################################################
# path of rar.exe
# rar.exe的路径
RAR_PATH = 'd:\\Program Files\\WinRAR\\rar'

# whether packege rar files, value: True or False
# 如果文件已经是RAR档，是否仍然打包。True（即使已经是RAR档也打包）；False（不打包rar档）
PACK_RAR_FILES = False

# if an input is a folder, packege the whole folder
# 如果输入是文件夹，是否整个文件夹打包。True（打包文件夹）；False（不打包文件夹）
PACK_WHOLE_DIR = False

# if the file size is smaller than SPLIT_SIZE, programe will still packege the file
# 是否打包小于SPLIT_SIZE的文件。True（打包小文件）；False（不打包小文件）
PACK_SMALL_FILE = False

# file will split if its size is large than this number. same as rar param -v
# if set it to 0, file will be packed even though it's very large 
# 分卷大小。单位为MB。设置为0时，不分卷
SPLIT_SIZE = 399

# same as rar param -m. 0-5
# 压缩模式。0-5依次为（存储、最快、较快、标准、较好、最好）
COMPRESS_MODE = 0

# same as rar param -rr.
# if set it to 0, no rr to be added
# 恢复记录百分比
RECOVER_PERCENT = 5  

# password, same as rar param -hp
# 密码。设置为空字符串时，不设置密码
PASSWORD = ""

# output rar files to a temp directory
# 打包文件的临时输出路径。设置为空字符串时，输出到文件所在路径
# windows下路径分隔符请使用双反斜杠\\，例如："D:\\user\\temp"
TMP_DIR = "z:\\temp"
##################################################################

rar_params = []

def _matchRARFile(file):
    rarfiles = []
    reRARFile = re.compile(re.escape(file) + "(\.part\d+|).rar")
    path = os.path.split(file)[0]
    filesInDir = os.listdir(path)
    for f in filesInDir:
        fpath = os.path.join(path,f)        
        if os.path.isdir(fpath) == True:
            continue
        if reRARFile.match(fpath) is not None:
            rarfiles.append(fpath)
    rarfiles.sort()
    return rarfiles

def matchRARFile(file):
    while True:
        rarfiles = _matchRARFile(file)
        # wait for files unlock
        # if waiting function return false, it means no more new rar part generate by other programe
        if not gadget.wait_for_files(rarfiles):
            return rarfiles
        time.sleep(5)

def set_params(options, tmp_path=''):
    '''
    options
    :v - SPLIT_SIZE
    :m - COMPRESS_MODE
    :rr - RECOVER_PERCENT
    :hp - PASSWORD
    :rar - EXCLUCE_RAR_FILES
    :s - PACK_SMALL_FILE
    :w - PACK_WHOLE_DIR
    '''
    global rar_params
    global RAR_PATH
    global PACK_RAR_FILES
    global PACK_WHOLE_DIR
    global PACK_SMALL_FILE
    global SPLIT_SIZE
    global COMPRESS_MODE
    global RECOVER_PERCENT
    global PASSWORD
    global TMP_DIR
    
    if tmp_path:
        TMP_DIR = tmp_path
    options = options.split(';')
    for op in options:
        op = op.split(':')
        if len(op) != 2:
            continue
        if op[0] == 'v':
            SPLIT_SIZE = int(op[1])
        elif op[0] == 'm':
            COMPRESS_MODE = int(op[1])
        elif op[0] == 'rr':
            RECOVER_PERCENT = int(op[1])
        elif op[0] == 'hp':
            PASSWORD = op[1].encode(sys.getfilesystemencoding())
        elif op[0] == 'rar':
            if op[1] == '0':
                PACK_RAR_FILES = False
            else:
                PACK_RAR_FILES = True
        elif op[0] == 's':
            if op[1] == '0':
                PACK_SMALL_FILE = False
            else:
                PACK_SMALL_FILE = True
        elif op[0] == 'w':
            if op[1] == '0':
                PACK_WHOLE_DIR = False
            else:
                PACK_WHOLE_DIR = True
                
    #reset global params var
    rar_params = []
    rar_params.append(RAR_PATH)
    rar_params.append("a")
    if SPLIT_SIZE > 0:
        rar_params.append("-v%dm" % SPLIT_SIZE)
    rar_params.append("-m%d" % COMPRESS_MODE)
    if RECOVER_PERCENT > 0:
        rar_params.append("-rr%dp" % RECOVER_PERCENT)
    if PASSWORD:
        rar_params.append("-hp%s" % PASSWORD)
    rar_params.append('-ep1')
    #rar_params.append('-r')
    return rar_params
    

def rar(file, options='', efilter='', tmp_path=''):
    '''
    options should be formed like v:300;m:0;w:1
    '''
    global filter
    filter = efilter
    set_params(options, tmp_path)
    if os.path.isdir(file):
        dir = file
        if PACK_WHOLE_DIR:
#            rar_params.append('-r')
            return rar_one_item(dir)
        else:
            filelist = gadget.walkDir(dir)
            rarlist = []
            for f in filelist:
                rarlist.extend(rar_one_file(f))
            return rarlist
    elif os.path.isfile(file):
        return rar_one_file(file)
    else:
        return []

    
def rar_one_file(file):
    # don't pack rar file    
    ext = os.path.splitext(file)[1]
    if ext == '.rar' and not PACK_RAR_FILES:
        gadget.write_line_with_sep(sys.stderr, "%s is a rar file, program won't package it."%file)
        return [file,]
    
    # don't pack small file
    filesize = os.path.getsize(file)
    if not PACK_SMALL_FILE and filesize < SPLIT_SIZE * 1024 * 1024:
        return [file,]
    
    return rar_one_item(file)
    
def rar_one_item(file):
    #exclude files before packing
    filelist = gadget.file_filter([file,], filter)
    if not filelist:
        return []
    file = os.path.realpath(file)
    target = file  
    
    if TMP_DIR:
        if not os.path.isdir(TMP_DIR):
            os.makedirs(TMP_DIR)
        target = os.path.join(TMP_DIR, os.path.split(target)[1])
        
    target = gadget.get_safety_str(target)
    
    while True:
        #check for existed rar files before run cmd
        exsitedRARs = matchRARFile(target)
        if len(exsitedRARs):
            gadget.write_line_with_sep(sys.stderr, "%s seems to has been packaged, omit it" % file)
            return exsitedRARs
         
        params = list(rar_params)
        params.append(target + '.rar')
        params.append(file)

        p = subprocess.Popen(params)
        p.wait()
        if not p.returncode:
            break
        else:
            gadget.write_line_with_sep(sys.stderr, "RAR process failed, wait 30s to retry")
            time.sleep(60) 

    rarfiles = matchRARFile(target)
    return rarfiles

    
if __name__ == "__main__":
    for i in sys.argv[1:]:
        print((rar(i)))
    
    